﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;
using System.Diagnostics;
using Microsoft.Win32;
using System.Reflection;

// fix: copy必须重构，没有进度怎么行？不可靠嘛。
// todo: move必须重构，没有进度怎么行？不可靠嘛。
// fix: 增加功能ctrl+d ,复制一个文件，等于是ctrl+c 然后ctrl+v ，更加快速，很常用
// fix: 多便签商量下，是不是要支持？
// todo: 能够打开特殊目录，比如startmenu,system32,controlpanel
// todo : 能够定义文件夹组，比如devgroup,sysgroup(全部特殊目录）,entertainment group(music ,photo),db group(比如访问数据库的表，存储过程),net group
namespace Easycmd
{
    class FolderTabControl : TabControl
    {
        public FolderTabPage SelectedPage
        {
            get{return (FolderTabPage)SelectedTab;}
        }
        public FolderTabPage Page(int index)
        {
            return ((FolderTabPage)(TabPages[index]));
        }
    }
    public enum CopyConfirm { YesToAll, NoToAll, Yes, No, NoSet }
    public class FolderListView : ListView
    {
    }
    public class Section : Panel, IWatcherSink
    {
        FolderListView view = new FolderListView();
        FSWatcher watcher = null;
        FolderTabControl tabs;

        internal FolderTabControl Tabs
        {
            get { return tabs; }            
        }
        public FolderListView View
        {
            get { return view; }
            set { view = value; }
        }
        FlowLayoutPanel flowPanel = new FlowLayoutPanel();
        Label label = new Label();
        Section peer = null;
        bool isActive = false;

        public bool IsActive
        {
            get { return isActive; }
            set { isActive = value; }
        }
        internal Section Peer
        {
            get { return peer; }
            set { peer = value; }
        }
        public Label Label
        {
            get { return label; }
            set { label = value; }
        }
        public Section()
        {
            // fill listview and flowpanel 
            view.Dock = DockStyle.Fill;
            this.Controls.Add(view);
            flowPanel.Dock = DockStyle.Top;
            flowPanel.Height = 30;
            this.Controls.Add(flowPanel);
            label.Width = 900;
            flowPanel.Height = 22;
            flowPanel.Controls.Add(label);
            // init tabControl
            tabs = new FolderTabControl ();
            tabs.TabStop = false;
            tabs.Height = 24;
            tabs.Dock = DockStyle.Top;
            tabs.Click += new EventHandler(tabs_Click);
            this.Controls.Add(tabs);
            //
            view.GridLines = true;
            // fill data ,init event and fswatcher
            FileViewUtils.InitListView(view);
            this.Dock = DockStyle.Fill;
            view.Enter += lvEnter;
            view.DoubleClick += lvDoubleClick;
            view.KeyDown += lvKeyDown;
            oldColor = label.BackColor;
            watcher = new FSWatcher(this);
        }

        void tabs_Click(object sender, EventArgs e)
        {
            View.Focus();
        }

        private void lvKeyDown(object sender, KeyEventArgs e)
        {
            DoKeyUp(sender, e);
        }
        Color oldColor;
        private void lvEnter(object sender, EventArgs e)
        {
            isActive = true;
            peer.isActive = false;

            label.BackColor = Color.Chocolate;
            peer.label.BackColor = oldColor;
            EnsureHasSelectedItem();
        }

        private void lvDoubleClick(object sender, EventArgs e)
        {
            isActive = true;
            peer.isActive = false;
            Execute();
        }
        private bool CheckSelected()
        {
            return Util.CheckError(view.SelectedItems.Count == 0);
        }
        private void Execute()
        {
            try
            {
                if (CheckSelected()) return;
                string selectedFile = GetSelected();
                if (FileUtils.IsDir(selectedFile))
                    EnterDir(selectedFile);
                else
                {
                    CountUsage();
                    FileUtils.ExecuteFile(selectedFile);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void CountUsage()
        {
            mru.CountUsage(CurrDir);
        }
        private string currDir = null;

        public string CurrDir
        {
            get { return currDir; }
            set {
                if (currDir != value)
                {                 
                    label.Text = value;                    
                    FileViewUtils.FillDir(view, value);                    
                }
                else
                {
                    FileViewUtils.FillDirIncrement(view, CurrDir);
                }
                currDir = value;
                EnsureHasSelectedItem();
                watcher.WatchChange(currDir, "*.*");
                // tabPage change with this
                tabs.SelectedPage.Dir = currDir;
            }
        }
        internal void EnterDir(string dir)
        {
            if (dir != "" && Directory.Exists(dir))
            {
                //Refresh(dir);
                CurrDir = dir;
            }
        }
        // enter dir which current label assigned 
        internal void EnterDir()
        {
            string dir = tabs.SelectedPage.Dir;
            EnterDir(dir);
        }      
        private void EnsureHasSelectedItem()
        {
            if (view.Items.Count > 0 && view.SelectedIndices.Count == 0)
            {
                view.SelectedIndices.Add(0);
                view.Items[0].Focused = true;
            }
        }
        private string GetSelected()
        {
            if (view.SelectedItems.Count > 0)
            {
                string path = FileUtils.CheckSlash(CurrDir) + view.SelectedItems[0].Text;
                if (FileUtils.IsDir(path))
                {
                    path = FileUtils.CheckSlash(path);
                }
                return path;
            }
            else
                return "";
        }
        private string GetSelectedText()
        {
            if (view.SelectedItems.Count > 0)
                return view.SelectedItems[0].Text;
            else
                return "";
        }
        private void btnRename_Click(object sender, EventArgs e)
        {
            Rename();
        }

        public void Rename()
        {
            CheckSelected();
            string name = GetSelectedText();
            string dir = GetSelected();
            string newname = InputBox.get("New name : ", name);
            string newfile = null;
            if (Util.CheckError(newname == "")) return;
            mru.CountUsage(CurrDir);
            newfile = CurrDir + "\\" + newname;
            try
            {
                Directory.Move(dir, newfile);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message);
            }
            FileViewUtils.FillDirIncrement(view, CurrDir);
            SelectDir((new FileInfo(newfile).Name));
        }




        private void DoKeyUp(object sender, KeyEventArgs e)
        {
            if (!e.Handled)
            {
                //Text = e.KeyValue.ToString();
                if (220 == e.KeyValue && e.Control)// ctrl + \ 
                {
                    Root();
                }
                else if (e.KeyCode == Keys.Back)// backspace  
                {
                    UpDir();
                }
                //else if (46 == e.KeyValue)// del
                else if (e.KeyCode == Keys.Delete)// del
                {
                    DeleteSelected();
                }
                else if (e.KeyCode == Keys.Enter)//Enter
                {
                    Execute();
                } if (e.KeyCode == Keys.W && e.Control)
                {
                   
                }
                else
                    //MessageBox.Show(e.KeyValue.ToString());// 34 pagedown ,33, pageup,32 space ,27 esc
                    if (e.KeyCode == Keys.Space) { }
                //MessageBox.Show("1");
            }
        }


        internal void UpDir()
        {
            if (!FileUtils.IsRoot(CurrDir))
            {
                string prevDir = CurrDir;
                CurrDir = FileUtils.ParentDir(CurrDir);
                SelectDir(new DirectoryInfo(prevDir).Name);
            }
        }

        private void SelectDir(string dir)
        {
            view.SelectedIndices.Clear();
            foreach (ListViewItem lvi in view.Items)
            {
                string d = lvi.Text;
                if (FileUtils.EqualsDir(dir, d))
                {
                    lvi.Selected = true;
                    lvi.Focused = true;
                    break;
                }
            }
        }
        private void SelectFile(string file)
        {
            EnterDir(FileUtils.ParentDir(file));
            ListView lvActive = view;
            foreach (ListViewItem lvi in lvActive.Items)
            {
                FileInfo fi = new FileInfo(file);
                if (lvi.Text == fi.Name)
                {
                    if (lvActive.SelectedIndices.Count > 0)
                        lvActive.SelectedIndices.Clear();
                    lvi.Selected = true;
                    lvi.Focused = true;
                    break;
                }
            }
        }
        private void lvLeftKeyDown(object sender, KeyEventArgs e)
        {
            DoKeyUp(sender, e);
        }


        private MruList mru = new MruList();
        public void DeleteSelected()
        {
            try
            {
                if (Util.CheckError(view.SelectedItems.Count == 0, "no file(s) selected ")) return;
                if (Util.CheckError(!Dlg.Confirm("Confirm Delete ?"))) return;
                CountUsage();
                foreach (ListViewItem lvi in view.SelectedItems)
                {
                    FileUtils.DeleteFileOrFolder(GetSelected());
                    lvi.Remove();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        internal void Root()
        {
            DirectoryInfo di = new DirectoryInfo(CurrDir);
            if (di.ToString() != di.Root.ToString())
            {
                CurrDir = di.Root.ToString();                
            }
        }
        [Obsolete("have not process bar ")]
        public string DoMove1()
        {
            string result = "";
            ListView SrcLV = view;
            string SrcDir = CurrDir;
            string DstDir = peer.CurrDir;
            foreach (ListViewItem lvi in SrcLV.SelectedItems)
            {
                string fullname = lvi.Text;
                fullname = FileUtils.CheckSlash(SrcDir) + fullname;
                string dst = "";
                if (Directory.Exists(fullname))
                {
                    string srcName = (new DirectoryInfo(fullname).Name);
                    dst = FileUtils.CheckSlash(DstDir) + srcName + "\\";
                    Directory.CreateDirectory(dst);
                }
                else
                {
                    dst = FileUtils.CheckSlash(DstDir);
                }
                CmdMove moveCmd = new CmdMove(fullname, dst);
                moveCmd.Run();
                result += moveCmd.FullCmd + "\n\n" + moveCmd.StdOut + "\n\n";
            }
            //FileViewUtils.FillDirIncrement(view, CurrDir);
            //FileViewUtils.FillDirIncrement(peer.view, peer.CurrDir);
            return result;
        }
        public string DoMove()
        {
            string result = "";
            ListView SrcLV = view;
            string Src = CurrDir;
            string Dst = peer.CurrDir;
            List<string> list = new List<string>();
            foreach (ListViewItem lvi in SrcLV.SelectedItems)
            {
                list.Add(lvi.Text);                
            }
            MoveProgressForm mf = new MoveProgressForm();
            MoveCmd cmd = new MoveCmd(Src, Dst, mf);
            
            //mf.WindowState = FormWindowState.Maximized;
            mf.TopMost = true;
            mf.Show();
            cmd.Action(list.ToArray());            
            return result;
        }
        public string DoCopy_1()
        {
            CopyFilesCmd cmd = new CopyFilesCmd(CurrDir, peer.CurrDir);
            foreach (ListViewItem lvi in view.SelectedItems)
            {
                cmd.AddFile(lvi.Text);                
            }
            cmd.CopyAsync(this);
            return "";
        }
        [Obsolete]
        public string DoCopy()
        {
            string result = "";
            ListView SrcLV = view;
            string SrcDir = CurrDir;
            string DstDir = peer.CurrDir;
            
            CopyCmd copy = new CopyCmd(0);
            CopyProcessForm processForm = new CopyProcessForm(GetTotalFiles());
            copy.ProcessForm = processForm;
            try
            {
                processForm.Show();
                processForm.CopyCmd = copy;        
                copy.SrcDir = SrcDir;
                copy.DstDir = DstDir;
                copy.FileName = new string[SrcLV.SelectedItems.Count];
                int i = 0 ;
                foreach (ListViewItem lvi in SrcLV.SelectedItems)                
                {                    
                    copy.FileName[i] = lvi.Text;
                    i++;
                }
                copy.Run();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                processForm.SetCloseEnable(true) ;
            }
            // 现在内置有watcher 了，不必自己刷新了。
            //FileViewUtils.FillDirIncrement(peer.view, peer.CurrDir);
            return result;
        }

        

        private int GetTotalFiles()
        {
            int answer = 0;
            ListView SrcLV = view;
            string SrcDir = CurrDir;            
            foreach (ListViewItem lvi in SrcLV.SelectedItems)
            {
                string fullname = lvi.Text;
                fullname = FileUtils.CheckSlash(SrcDir) + fullname;                
                string srcName = (new DirectoryInfo(fullname).Name);
                if (Directory.Exists(fullname))
                {                    
                    answer += FileUtils.GetTotalFiles(fullname);
                }
                else
                {
                    answer++;
                }
            }
            return answer;
        }

      
        /*
        public string DoCopy_1()
        {
            string result = "";
            ListView SrcLV = view;
            string SrcDir = CurrDir;
            string DstDir = peer.CurrDir;
            foreach (ListViewItem lvi in SrcLV.SelectedItems)
            {
                string fullname = lvi.Text;
                fullname = FileUtils.CheckSlash(SrcDir) + fullname;
                string dst = "";
                if (Directory.Exists(fullname))
                {
                    string srcName = (new DirectoryInfo(fullname).Name);
                    dst = FileUtils.CheckSlash(DstDir) + srcName + "\\";
                    Directory.CreateDirectory(dst);
                }
                else
                {
                    dst = FileUtils.CheckSlash(DstDir);
                }
                CmdCopy copyCmd = new CmdCopy(fullname, dst);
                copyCmd.Run();
                result += copyCmd.FullCmd + "\n\n" + copyCmd.StdOut + "\n\n";
            }
            // 现在内置有watcher 了，不必自己刷新了。
            //FileViewUtils.FillDirIncrement(peer.view, peer.CurrDir);
            return result;
        }
        */

        internal void ZipUnZip()
        {
            string file = GetSelected();
            if (Directory.Exists(file))
            {
                string zipFile = file;
                FileUtils.CheckNoSlash(ref zipFile);
                ZipHelper.ZipFiles(file, zipFile + ".zip", "");
                Refresh();
            }
            else if (File.Exists(file))
            {
                FileInfo fi = new FileInfo(file);
                if (fi.Extension == ".zip")
                {
                    string outputFile = CurrDir + fi.Name.Substring(0, fi.Name.Length - 4);
                    if (Directory.Exists(outputFile))
                        MessageBox.Show("zip to folder is exists,can not continue !");
                    else
                    {
                        Directory.CreateDirectory(outputFile);
                        ZipHelper.UnZipFiles(file, outputFile, "", false);
                        Refresh();
                    }
                }
            }
        }

        internal void Sync()
        {
            this.peer.EnterDir(GetSelected());
        }

        internal void SwitchDir()
        {
            string newdir = "";
            newdir = InputBox.get("Switch to directory:", CurrDir);
            if (newdir != "")
            {

                if (newdir.Substring(0, 2) != "\\\\")// !  net share
                {
                    EnterDir(newdir);
                }
                else
                {
                    if (FileUtils.CheckUnc(newdir))
                    {
                        EnterDir(newdir);
                    }
                }
            }
        }

        internal void NewDir()
        {
            string dir = CurrDir;
            DirectoryInfo di = new DirectoryInfo(dir);
            string newdir = InputBox.get("New directory name:", "");
            if (newdir != "")
            {
                di.CreateSubdirectory(newdir);
                CurrDir = dir;                
                SelectDir(newdir);
            }
        }

        internal void DoSearch()
        {
            CountUsage();
            string file = SearchFile.get(CurrDir);
            if (file != "")
                SelectFile(file);
        }



        internal void DoNewText()
        {
            CountUsage();
            string newfile = FileUtils.GetNewFile(CurrDir);
            using (StreamWriter sw = File.CreateText(newfile))
            {
                sw.WriteLine("Create by Easycmd .");
                sw.Close();
            }
            ListViewItem item = FileViewUtils.FillFile(this.view, newfile);
            if (item != null)
            {
                this.view.SelectedIndices.Clear();
                item.Selected = true;
                item.Focused = true;
            }
        }

        internal void FolderSize()
        {
            try
            {
                string currdir = CurrDir;
                foreach (ListViewItem lvi in view.SelectedItems)
                {
                    string file = FileUtils.CheckSlash(currdir) + lvi.Text;
                    if (FileUtils.IsDir(file))
                    {
                        RefreshViewItemSize(lvi, FileUtils.GetDirSize(file));
                    }
                }
            }
            catch (Exception e) { MessageBox.Show(e.Message); }
        }
        private void RefreshViewItemSize(ListViewItem lvi, long p)
        {
            lvi.SubItems[2].Text = p.ToString();
        }



        internal void FullDirToCB()
        {
            if (view.SelectedItems.Count > 0)
            {
                string path = GetSelected();
                if (path != "")
                {
                    Clipboard.SetText(path);
                }
            }
        }

        internal void NameToCB()
        {
            if (view.SelectedItems.Count > 0)
            {
                string path = view.SelectedItems[0].Text;
                Clipboard.SetText(path);
            }
        }

        internal void EditText()
        {
            string file = GetSelected();
            if (!FileUtils.IsDir(file))
            {
                // get txt 's editor from registry
                CountUsage();
                CmdEditText edit = new CmdEditText(file);
                edit.Run();
            }
        }

        #region IWatcherSink Members

        void IWatcherSink.changed()
        {
            Invoke(new ThreadSafeCall(ThreadSafeSetCurrDir), new object[] { });
            
        }
        delegate void ThreadSafeCall(); 
        void ThreadSafeSetCurrDir()
        {
            CurrDir = CurrDir;
        }
        #endregion

        internal void NewLabel(string dir)
        {
            FolderTabPage page = new FolderTabPage(dir,view,this);
            //TabPage page = new TabPage();
            tabs.TabPages.Add(page);
            tabs.SelectTab(page);
            view.Focus();
        }

        internal void DoDuplicate()
        {
            CopyFilesCmd cmd = new CopyFilesCmd(CurrDir, CurrDir);
            foreach (ListViewItem lvi in view.SelectedItems)
            {
                cmd.AddFile(lvi.Text);
            }
            cmd.DuplicateAsync(this);
            
        }

        internal void CloseLabel()
        {
            if (tabs.TabCount > 1)
            {
                tabs.SelectedPage.Dispose();
                view.Focus();
            }
        }

        internal void NewLabel()
        {
            NewLabel(tabs.SelectedPage.Dir);
        }

        public string[] Dirs { get {
            List<string> list = new List<string>();
            for (int i = 0; i < Tabs.TabCount; i++)
                list.Add(tabs.Page(i).Dir);
            return list.ToArray();
        } }
    }
    class FolderTabPage : TabPage
    {
        string dir;

        public string Dir
        {
            get { return dir; }
            set { dir = value; Text = new DirectoryInfo(dir).Name; }
        }
        ListView view;
        Section section;
        public FolderTabPage(string dir,ListView view ,Section section)
        {
            this.section = section;
            this.dir = dir;
            this.view = view;
            Text = new DirectoryInfo(dir).Name;
            Enter += new EventHandler(FolderTabPage_Enter);
            Click += new EventHandler(FolderTabPage_Click);
        }

        void FolderTabPage_Click(object sender, EventArgs e)
        {
            
        }

        void FolderTabPage_Enter(object sender, EventArgs e)
        {
            section.EnterDir(dir);
        }
    }
}
